package com.logic.modular.game.room.service;

import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.comment.dubbo.service.PvpRoomService;
import com.logic.comment.exection.InfoTips;
import com.comment.exception.ServiceException;

import com.logic.comment.util.RedisUtils;
import com.logic.config.netty.web.service.MessageService;
import com.logic.modular.game.GameConstant;
import com.logic.modular.game.core.service.MatchServiceImpl;
import com.comment.pojo.domain.logic.core.PvpRoom;
import com.logic.modular.game.room.mapper.PvpRoomMapper;
import com.comment.pojo.domain.logic.domain.Player;
import com.comment.pojo.domain.logic.domain.PlayerStatus;
import com.logic.modular.game.player.info.service.PlayerServiceImpl;
import com.comment.pojo.domain.logic.core.PvpMatch;
import com.logic.modular.game.player.info.service.PlayerStatusServiceImpl;
import lombok.extern.slf4j.Slf4j;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 房间表(PvpRoom)表服务实现类
 *
 * @author cxy
 * @since 2024-11-06 15:25:58
 */
@Slf4j
@Service
@DubboService(interfaceClass = PvpRoomService.class)
public class PvpRoomServiceImpl extends ServiceImpl<PvpRoomMapper, PvpRoom>
    implements PvpRoomService
{
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private MatchServiceImpl pvpMatchServiceImpl;
    @Resource
    private PlayerStatusServiceImpl playerMatchServiceImpl;
    @Resource
    private PlayerServiceImpl playerServiceImpl;
    @Autowired
    private PlayerStatusServiceImpl playerStatusServiceImpl;

    /**
     * 获取 自己 加入的房间信息
     */
    @Override
    public PvpRoom  selectMyJoinRoom(Long playerId) {
        PlayerStatus playerStatus = playerStatusServiceImpl.get(playerId);
        return select(playerStatus.getRoomOwnerId());
    }


    public List<PvpRoom> allList() {
        return list().stream().peek(item -> item.setPwd("")).collect(Collectors.toList());
    }

    public PvpRoom select(Long roomOwner) {
        String format = String.format(GameConstant.PLAYER_ROM_KEY, roomOwner);
        PvpRoom pvpRoom = (PvpRoom) redisUtils.get(format);
        if (pvpRoom == null) {
            pvpRoom = getById(roomOwner);
            if (pvpRoom != null) {
                saveCache(pvpRoom);
            }
        }
        return pvpRoom;
    }

    private void updateByIdAndSaveCache(PvpRoom pvpRoom) {
        Player select = playerServiceImpl.select(pvpRoom.getRoomOwner());
        pvpRoom.setRoomName(select.getNickname()==null?"":select.getNickname());
        boolean b = pvpRoom.updateById();

        if (b) {
            saveCache(pvpRoom);
            for (Long player : pvpRoom.getPlayers()) {
                MessageService.sendMessageToUser(player, MessageService.updateJsonObject("pvpRoom", pvpRoom));
            }
        }
    }

    private void updateByIdAndSaveCache(Long roomOwnerId, PvpRoom pvpRoom) {
        boolean b = removeById(roomOwnerId);
        if (b) {
            boolean insert = pvpRoom.insert();
            if (insert) {
                log.info("完全更新成功");
                saveCache(pvpRoom);
                for (Long player : pvpRoom.getPlayers()) {
                    MessageService.sendMessageToUser(player, MessageService.updateJsonObject("pvpRoom", pvpRoom));
                }
            } else {
                log.info("完全更新失败");
            }
        }
    }

    public void clearCache(Long uid) {
        String format = String.format(GameConstant.PLAYER_ROM_KEY, uid);
        redisUtils.delete(format);
    }

    public void saveCache(PvpRoom pvpRoom) {
        Long roomOwner = pvpRoom.getRoomOwner();
        if (roomOwner == null) {
            throw new RuntimeException("roomOwner不能为空");
        }
        String format = String.format(GameConstant.PLAYER_ROM_KEY, pvpRoom.getRoomOwner());
        redisUtils.set(format, pvpRoom, 30L, TimeUnit.MINUTES);
    }

    /**
     * 创建房间
     *
     * @param playerId 房间-创建人id
     * @param password 房间-密码
     * @return 房间-信息
     */
    public PvpRoom createRoom(Long playerId, String password, Long mapId) {
        Player select = playerServiceImpl.select(playerId);
        PlayerStatus playerMatch = playerMatchServiceImpl.get(playerId);
        if (playerMatch.getCurrentMatchId() > 0) {
            throw new ServiceException("请先退出当前匹配");
        }
        if (playerMatch.getRoomOwnerId() > 0) {
            throw new ServiceException("已有房间" + playerMatch.getRoomOwnerId());
        }
        PvpRoom pvpRoom = new PvpRoom();
        pvpRoom.setRoomOwner(playerId);
        pvpRoom.setRoomName(select.getNickname());
        pvpRoom.setPwd(MD5.create().digestHex(password));
        pvpRoom.setRoomStatus(0);
        pvpRoom.setMapId(mapId);

        pvpRoom.insert();
        saveCache(pvpRoom);
        PvpRoom byId = getById(playerId);
        byId.roomPos.put(String.valueOf(1), playerId);
        byId.players.add(playerId);
        updateByIdAndSaveCache(byId);

        playerMatch.setRoomOwnerId(playerId);
        playerMatchServiceImpl.updateById(playerMatch);

        return byId;
    }


    /**
     * 踢人
     *
     * @param roomOwner 房主id
     * @param pos       位置
     * @return 房间-信息
     */
    public PvpRoom kickingPeople(Long roomOwner, Integer pos) {
        PvpRoom pvpRoom = select(roomOwner);
        if (pvpRoom == null) {
            return null;
        }
        long sourceValue = Long.parseLong(pvpRoom.roomPos.get(pos.toString()).toString());

        if (sourceValue > 0) { // 有玩家先踢出
            pvpRoom.roomPos.put(pos.toString(), 0L);
            pvpRoom.players.remove(sourceValue);
            pvpRoom.checkRoomStatus();
            updateByIdAndSaveCache(pvpRoom);
        }
        return pvpRoom;
    }

    /**
     * 关闭或打开座椅
     *
     * @param roomOwner 房主id
     * @param pos       位置
     * @return 房间-信息
     */
    public PvpRoom closeOrOpenTheSeat(Long roomOwner, Integer pos) {
        PvpRoom pvpRoom = select(roomOwner);
        if (pvpRoom == null) {
            return null;
        }
        long sourceValue = Long.parseLong(pvpRoom.roomPos.get(pos.toString()).toString());

        if (sourceValue > 0) { // 有玩家先踢出
            throw new InfoTips(String.format("座位有人,玩家:%d", sourceValue));
        }
        if (sourceValue == 0) {
            pvpRoom.roomPos.put(pos.toString(), -1L);
            pvpRoom.players.remove(sourceValue);
            pvpRoom.checkRoomStatus();
            updateByIdAndSaveCache(pvpRoom);
        }
        if (sourceValue == -1) {
            pvpRoom.roomPos.put(pos.toString(), 0L);
            pvpRoom.players.remove(sourceValue);
            pvpRoom.checkRoomStatus();
            updateByIdAndSaveCache(pvpRoom);
        }
        return pvpRoom;
    }

    /**
     * 住一个座位
     *
     * @param roomOwner 房主id
     * @param playerId  玩家id`
     * @param pos       位置
     * @return 房间-信息
     */
    public PvpRoom seizeASeat(Long roomOwner, Long playerId, Integer pos) {
        PvpRoom pvpRoom = select(roomOwner);
        if (pvpRoom == null || pvpRoom.getRoomStatus() == -1) {
            return null;
        }
        long sourceValue = Long.parseLong(pvpRoom.roomPos.get(pos.toString()).toString());

        if (sourceValue > 0) { // 有玩家先踢出
            throw new InfoTips(String.format("座位有人,玩家:%d", sourceValue));
        }
        if (sourceValue == 0) {
            pvpRoom.roomPos.put(pos.toString(), playerId);
            pvpRoom.players.add(playerId);
            pvpRoom.checkRoomStatus();
            updateByIdAndSaveCache(pvpRoom);
        }
        PlayerStatus playerMatch = playerMatchServiceImpl.get(playerId);
        playerMatch.setRoomOwnerId(roomOwner);
        playerMatchServiceImpl.updateById(playerMatch);
        return pvpRoom;
    }


    /**
     * 加入指定玩家房间
     *
     * @return 房间-信息
     */
    public PvpRoom joinRoom(Long playerId, Long roomOwner, String password) {
        PlayerStatus playerMatch = playerMatchServiceImpl.get(playerId);
        if (playerMatch.getCurrentMatchId() > 0) {
            throw new ServiceException("请先退出当前匹配");
        }
        if (playerMatch.getRoomOwnerId() > 0) {
            throw new ServiceException("已有房间" + playerMatch.getRoomOwnerId());
        }

        PvpRoom pvpRoom = select(roomOwner);
        if (pvpRoom == null) {
            throw new ServiceException("该房间号不正确");
        }
        Integer roomStatus = pvpRoom.getRoomStatus();
        switch (roomStatus) {
            case 0:
                break;
            case 1:
                throw new ServiceException("房间已满员");
            case 2:
                throw new ServiceException("游戏中");
            default:
                throw new RuntimeException("未知状态");
        }

        String pwd = MD5.create().digestHex(password);
        if (pvpRoom.getPwd() != null && !pvpRoom.getPwd().equals(pwd)) {
            throw new ServiceException("房间密码不正确");
        }
        if (pvpRoom.getPlayers().contains(playerId)) {
            throw new ServiceException("已再此房间");
        }

        // 获取空位
        Integer pos = pvpRoom.obtainNextEmptySeat();
        if (pos == null) {
            throw new ServiceException("房间已满员");
        }
        return seizeASeat(roomOwner, playerId, pos);
    }

    /**
     * 离开房间
     *
     * @param playerId 离开的玩家
     * @return 房间-信息
     */
    @Transactional
    public PvpRoom leaveRoom(Long playerId) {
        PlayerStatus playerMatch = playerMatchServiceImpl.get(playerId);
        if (playerMatch.getCurrentMatchId() > 0) {
            throw new ServiceException("请先退出当前匹配");
        }

        Long roomOwnerId = playerMatch.getRoomOwnerId();

        PvpRoom pvpRoom = select(roomOwnerId);

        boolean remove = pvpRoom.players.remove(playerId);
        if (!remove) throw new ServiceException("玩家不在此房间");

        boolean empty = pvpRoom.players.isEmpty();// 房间为空
        if (empty) {
            playerMatch.setRoomOwnerId(0L);
            playerMatchServiceImpl.updateById(playerMatch);
            clearRoomByOwnerId(roomOwnerId);
            return pvpRoom;
        }

        String pos = pvpRoom.obtainPlayerSeat(playerId);
        if (roomOwnerId.equals(playerId)) {
            // 房主离开
            pvpRoom.roomPos.put(pos, 0);

            // 新房主
            Long l = pvpRoom.obtainNextPlayer();
            pvpRoom.setRoomOwner(l);

            // 检测状态
            pvpRoom.checkRoomStatus();


            // 对玩家影响
            playerMatch.setRoomOwnerId(0L);
            playerMatchServiceImpl.updateById(playerMatch);

            // 新房主
            PlayerStatus newOwner = playerMatchServiceImpl.get(l);
            newOwner.setRoomOwnerId(l);
            playerMatchServiceImpl.updateById(newOwner);

            // 完全-更新-缓存-广播
            updateByIdAndSaveCache(roomOwnerId, pvpRoom);
        } else {// 普通玩家离开
            pvpRoom.roomPos.put(pos, 0);
            pvpRoom.checkRoomStatus();
            updateByIdAndSaveCache(pvpRoom);

            // 对玩家影响
            playerMatch.setRoomOwnerId(0L);
            playerMatchServiceImpl.updateById(playerMatch);
        }
        return pvpRoom;
    }

    /**
     * 开始游戏
     *
     * @param roomOwner 房主id
     * @return 比赛-信息
     */
    public PvpMatch startGame(Long roomOwner) {
        String token = "stopTheGame";
        if (redisUtils.hasKey(token)) {
            throw new ServiceException("禁赛中");
        }

        PvpRoom pvpRoom = select(roomOwner);
        Set<Long> players = pvpRoom.getPlayers();
        if (players.size() <= 1) {
            throw new ServiceException("人数不足");
        }

        PvpMatch pvpMatch = new PvpMatch(pvpRoom);
        boolean save = pvpMatchServiceImpl.save(pvpMatch);
        if (save) {
            Long pvpMatchId = pvpMatch.getId();
            for (Long playerId : pvpMatch.getPlayerCount()) {
                PlayerStatus playerMatch = playerMatchServiceImpl.get(playerId);
                playerMatch.setCurrentMatchId(pvpMatchId);
                playerMatchServiceImpl.updateById(playerMatch);
            }
            pvpRoom.setRoomStatus(2);
            pvpRoom.setMatchId(pvpMatchId);
            updateByIdAndSaveCache(pvpRoom);
            pvpMatchServiceImpl.startPvp(pvpMatch);
        }
        return pvpMatch;
    }

    /**
     * 清除房间
     */
    public void clearRoomByOwnerId(Long ownerId) {
        if (select(ownerId).deleteById()) {
            clearCache(ownerId);
        }
    }

    /**
     * 清除房间
     */
    public void clearRoomByMatchId(Long matchId) {
        PvpRoom select = getOne(new LambdaQueryWrapper<PvpRoom>().eq(PvpRoom::getMatchId, matchId));
        if (select == null) {
            return;
        }
        select.checkRoomStatus();
        updateByIdAndSaveCache(select);
    }
}
